import stringWidth from 'string-width';

function stringVisualWidth(str) {
  return stringWidth(str);
}

function splitStringByVisualWidth(str, maxWidth) {
  const result = [];
  let currentChunk = '';
  let currentWidth = 0;

  for (let i = 0; i < str.length; i++) {
    const char = str[i];
    const charWidth = stringWidth(char); // 计算当前字符的视觉宽度

    // 如果添加当前字符后，当前块的视觉宽度会超过最大宽度
    if (currentWidth + charWidth > maxWidth) {
      // 如果当前块不为空，则将其添加到结果中
      if (currentChunk.length > 0) {
        result.push(currentChunk);
      }
      // 重置当前块和宽度，并从当前字符开始新的块
      currentChunk = char;
      currentWidth = charWidth;
    } else {
      // 否则，将当前字符添加到当前块中
      currentChunk += char;
      currentWidth += charWidth;
    }
  }

  // 将最后一个块（如果存在）添加到结果中
  if (currentChunk.length > 0) {
    result.push(currentChunk);
  }

  return result;
}

/**
 * 根据视觉宽度从字符串中提取子字符串。
 *
 * @param {string} str - 原始字符串。
 * @param {number} startVisualWidth - 子字符串的起始视觉宽度（包含）。
 * @param {number} [lengthVisualWidth] - 子字符串的所需视觉长度。如果未提供、为 null 或为负数，则截取到字符串末尾。
 * @returns {string} 提取的子字符串。
 */
function substringByVisualWidth(str, startVisualWidth, lengthVisualWidth) {
  // 1. 参数校验和初始化
  if (startVisualWidth < 0) {
    startVisualWidth = 0;
  }

  // 判断是否需要截取到字符串末尾
  const toEnd =
    lengthVisualWidth === undefined || lengthVisualWidth === null || lengthVisualWidth < 0;

  // 如果明确指定长度为 0 且不是截取到末尾，则直接返回空字符串
  if (!toEnd && lengthVisualWidth === 0) {
    return '';
  }

  let currentTotalVisualWidth = 0;
  let actualStartIndex = 0; // 子字符串在原始字符串中的实际字符起始索引

  // 2. 确定子字符串的实际字符起始索引 (actualStartIndex)
  // 遍历字符串，找到第一个视觉宽度累加超过或等于 startVisualWidth 的字符
  for (let i = 0; i < str.length; i++) {
    const char = str[i];
    const charW = stringWidth(char);

    // 如果当前累积宽度加上当前字符的宽度会超过 startVisualWidth
    // 那么这个字符就是子字符串的起始字符
    if (currentTotalVisualWidth + charW > startVisualWidth) {
      actualStartIndex = i;
      break;
    }
    currentTotalVisualWidth += charW;
    actualStartIndex = i + 1; // 如果当前字符完全在 startVisualWidth 之前，则跳过它
  }

  // 如果 startVisualWidth 超出了整个字符串的视觉宽度，则返回空字符串
  // 这里的条件是：循环结束后 actualStartIndex 已经到达或超过 str.length，
  // 并且实际累积的视觉宽度 currentTotalVisualWidth 仍然小于 startVisualWidth。
  if (actualStartIndex >= str.length && currentTotalVisualWidth < startVisualWidth) {
    return '';
  }

  let extractedVisualWidth = 0;
  let actualEndIndex = actualStartIndex; // 子字符串在原始字符串中的实际字符结束索引（不包含）

  // 3. 确定子字符串的实际字符结束索引 (actualEndIndex)
  if (toEnd) {
    // 如果 lengthVisualWidth 未提供或为负数，则截取到字符串末尾
    actualEndIndex = str.length;
  } else {
    // 如果 lengthVisualWidth 已提供，则从 actualStartIndex 开始遍历，累加视觉宽度直到达到 lengthVisualWidth
    for (let i = actualStartIndex; i < str.length; i++) {
      const char = str[i];
      const charW = stringWidth(char);

      // 如果当前已提取的视觉宽度加上当前字符的宽度会超过 lengthVisualWidth
      // 那么子字符串应该在当前字符之前结束
      if (extractedVisualWidth + charW > lengthVisualWidth) {
        actualEndIndex = i;
        break;
      }
      extractedVisualWidth += charW;
      actualEndIndex = i + 1; // 包含当前字符
    }
  }

  // 4. 提取子字符串
  return str.substring(actualStartIndex, actualEndIndex);
}

export { splitStringByVisualWidth, substringByVisualWidth, stringVisualWidth };
